home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2000 March / maximum-cd-2000-03.iso / Quake3 Game Source / Q3AGameSource.exe / Main / ui_mfield.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-18  |  8.2 KB  |  420 lines

  1. // Copyright (C) 1999-2000 Id Software, Inc.
  2. //
  3. #include "ui_local.h"
  4.  
  5. /*
  6. ===================
  7. MField_Draw
  8.  
  9. Handles horizontal scrolling and cursor blinking
  10. x, y, are in pixels
  11. ===================
  12. */
  13. void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color ) {
  14.     int        len;
  15.     int        charw;
  16.     int        drawLen;
  17.     int        prestep;
  18.     int        cursorChar;
  19.     char    str[MAX_STRING_CHARS];
  20.  
  21.     drawLen = edit->widthInChars;
  22.     len     = strlen( edit->buffer ) + 1;
  23.  
  24.     // guarantee that cursor will be visible
  25.     if ( len <= drawLen ) {
  26.         prestep = 0;
  27.     } else {
  28.         if ( edit->scroll + drawLen > len ) {
  29.             edit->scroll = len - drawLen;
  30.             if ( edit->scroll < 0 ) {
  31.                 edit->scroll = 0;
  32.             }
  33.         }
  34.         prestep = edit->scroll;
  35.     }
  36.  
  37.     if ( prestep + drawLen > len ) {
  38.         drawLen = len - prestep;
  39.     }
  40.  
  41.     // extract <drawLen> characters from the field at <prestep>
  42.     if ( drawLen >= MAX_STRING_CHARS ) {
  43.         trap_Error( "drawLen >= MAX_STRING_CHARS" );
  44.     }
  45.     memcpy( str, edit->buffer + prestep, drawLen );
  46.     str[ drawLen ] = 0;
  47.  
  48.     UI_DrawString( x, y, str, style, color );
  49.  
  50.     // draw the cursor
  51.     if (!(style & UI_PULSE)) {
  52.         return;
  53.     }
  54.  
  55.     if ( trap_Key_GetOverstrikeMode() ) {
  56.         cursorChar = 11;
  57.     } else {
  58.         cursorChar = 10;
  59.     }
  60.  
  61.     style &= ~UI_PULSE;
  62.     style |= UI_BLINK;
  63.  
  64.     if (style & UI_SMALLFONT)
  65.     {
  66.         charw =    SMALLCHAR_WIDTH;
  67.     }
  68.     else if (style & UI_GIANTFONT)
  69.     {
  70.         charw =    GIANTCHAR_WIDTH;
  71.     }
  72.     else
  73.     {
  74.         charw =    BIGCHAR_WIDTH;
  75.     }
  76.  
  77.     if (style & UI_CENTER)
  78.     {
  79.         len = strlen(str);
  80.         x = x - len*charw/2;
  81.     }
  82.     else if (style & UI_RIGHT)
  83.     {
  84.         len = strlen(str);
  85.         x = x - len*charw;
  86.     }
  87.     
  88.     UI_DrawChar( x + ( edit->cursor - prestep ) * charw, y, cursorChar, style & ~(UI_CENTER|UI_RIGHT), color );
  89. }
  90.  
  91. /*
  92. ================
  93. MField_Paste
  94. ================
  95. */
  96. void MField_Paste( mfield_t *edit ) {
  97.     char    pasteBuffer[64];
  98.     int        pasteLen, i;
  99.  
  100.     trap_GetClipboardData( pasteBuffer, 64 );
  101.  
  102.     // send as if typed, so insert / overstrike works properly
  103.     pasteLen = strlen( pasteBuffer );
  104.     for ( i = 0 ; i < pasteLen ; i++ ) {
  105.         MField_CharEvent( edit, pasteBuffer[i] );
  106.     }
  107. }
  108.  
  109. /*
  110. =================
  111. MField_KeyDownEvent
  112.  
  113. Performs the basic line editing functions for the console,
  114. in-game talk, and menu fields
  115.  
  116. Key events are used for non-printable characters, others are gotten from char events.
  117. =================
  118. */
  119. void MField_KeyDownEvent( mfield_t *edit, int key ) {
  120.     int        len;
  121.  
  122.     // shift-insert is paste
  123.     if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && trap_Key_IsDown( K_SHIFT ) ) {
  124.         MField_Paste( edit );
  125.         return;
  126.     }
  127.  
  128.     len = strlen( edit->buffer );
  129.  
  130.     if ( key == K_DEL || key == K_KP_DEL ) {
  131.         if ( edit->cursor < len ) {
  132.             memmove( edit->buffer + edit->cursor, 
  133.                 edit->buffer + edit->cursor + 1, len - edit->cursor );
  134.         }
  135.         return;
  136.     }
  137.  
  138.     if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) 
  139.     {
  140.         if ( edit->cursor < len ) {
  141.             edit->cursor++;
  142.         }
  143.         if ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )
  144.         {
  145.             edit->scroll++;
  146.         }
  147.         return;
  148.     }
  149.  
  150.     if ( key == K_LEFTARROW || key == K_KP_LEFTARROW ) 
  151.     {
  152.         if ( edit->cursor > 0 ) {
  153.             edit->cursor--;
  154.         }
  155.         if ( edit->cursor < edit->scroll )
  156.         {
  157.             edit->scroll--;
  158.         }
  159.         return;
  160.     }
  161.  
  162.     if ( key == K_HOME || key == K_KP_HOME || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {
  163.         edit->cursor = 0;
  164.         edit->scroll = 0;
  165.         return;
  166.     }
  167.  
  168.     if ( key == K_END || key == K_KP_END || ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {
  169.         edit->cursor = len;
  170.         edit->scroll = len - edit->widthInChars + 1;
  171.         if (edit->scroll < 0)
  172.             edit->scroll = 0;
  173.         return;
  174.     }
  175.  
  176.     if ( key == K_INS || key == K_KP_INS ) {
  177.         trap_Key_SetOverstrikeMode( !trap_Key_GetOverstrikeMode() );
  178.         return;
  179.     }
  180. }
  181.  
  182. /*
  183. ==================
  184. MField_CharEvent
  185. ==================
  186. */
  187. void MField_CharEvent( mfield_t *edit, int ch ) {
  188.     int        len;
  189.  
  190.     if ( ch == 'v' - 'a' + 1 ) {    // ctrl-v is paste
  191.         MField_Paste( edit );
  192.         return;
  193.     }
  194.  
  195.     if ( ch == 'c' - 'a' + 1 ) {    // ctrl-c clears the field
  196.         MField_Clear( edit );
  197.         return;
  198.     }
  199.  
  200.     len = strlen( edit->buffer );
  201.  
  202.     if ( ch == 'h' - 'a' + 1 )    {    // ctrl-h is backspace
  203.         if ( edit->cursor > 0 ) {
  204.             memmove( edit->buffer + edit->cursor - 1, 
  205.                 edit->buffer + edit->cursor, len + 1 - edit->cursor );
  206.             edit->cursor--;
  207.             if ( edit->cursor < edit->scroll )
  208.             {
  209.                 edit->scroll--;
  210.             }
  211.         }
  212.         return;
  213.     }
  214.  
  215.     if ( ch == 'a' - 'a' + 1 ) {    // ctrl-a is home
  216.         edit->cursor = 0;
  217.         edit->scroll = 0;
  218.         return;
  219.     }
  220.  
  221.     if ( ch == 'e' - 'a' + 1 ) {    // ctrl-e is end
  222.         edit->cursor = len;
  223.         edit->scroll = edit->cursor - edit->widthInChars + 1;
  224.         if (edit->scroll < 0)
  225.             edit->scroll = 0;
  226.         return;
  227.     }
  228.  
  229.     //
  230.     // ignore any other non printable chars
  231.     //
  232.     if ( ch < 32 ) {
  233.         return;
  234.     }
  235.  
  236.     if ( !trap_Key_GetOverstrikeMode() ) {    
  237.         if ((edit->cursor == MAX_EDIT_LINE - 1) || (edit->maxchars && edit->cursor >= edit->maxchars))
  238.             return;
  239.     } else {
  240.         // insert mode
  241.         if (( len == MAX_EDIT_LINE - 1 ) || (edit->maxchars && len >= edit->maxchars))
  242.             return;
  243.         memmove( edit->buffer + edit->cursor + 1, edit->buffer + edit->cursor, len + 1 - edit->cursor );
  244.     }
  245.  
  246.     edit->buffer[edit->cursor] = ch;
  247.     if (!edit->maxchars || edit->cursor < edit->maxchars-1)
  248.         edit->cursor++;
  249.  
  250.     if ( edit->cursor >= edit->widthInChars )
  251.     {
  252.         edit->scroll++;
  253.     }
  254.  
  255.     if ( edit->cursor == len + 1) {
  256.         edit->buffer[edit->cursor] = 0;
  257.     }
  258. }
  259.  
  260. /*
  261. ==================
  262. MField_Clear
  263. ==================
  264. */
  265. void MField_Clear( mfield_t *edit ) {
  266.     edit->buffer[0] = 0;
  267.     edit->cursor = 0;
  268.     edit->scroll = 0;
  269. }
  270.  
  271. /*
  272. ==================
  273. MenuField_Init
  274. ==================
  275. */
  276. void MenuField_Init( menufield_s* m ) {
  277.     int    l;
  278.     int    w;
  279.     int    h;
  280.  
  281.     MField_Clear( &m->field );
  282.  
  283.     if (m->generic.flags & QMF_SMALLFONT)
  284.     {
  285.         w = SMALLCHAR_WIDTH;
  286.         h = SMALLCHAR_HEIGHT;
  287.     }
  288.     else
  289.     {
  290.         w = BIGCHAR_WIDTH;
  291.         h = BIGCHAR_HEIGHT;
  292.     }    
  293.  
  294.     if (m->generic.name) {
  295.         l = (strlen( m->generic.name )+1) * w;        
  296.     }
  297.     else {
  298.         l = 0;
  299.     }
  300.  
  301.     m->generic.left   = m->generic.x - l;
  302.     m->generic.top    = m->generic.y;
  303.     m->generic.right  = m->generic.x + w + m->field.widthInChars*w;
  304.     m->generic.bottom = m->generic.y + h;
  305. }
  306.  
  307. /*
  308. ==================
  309. MenuField_Draw
  310. ==================
  311. */
  312. void MenuField_Draw( menufield_s *f )
  313. {
  314.     int        x;
  315.     int        y;
  316.     int        w;
  317.     int        h;
  318.     int        style;
  319.     qboolean focus;
  320.     float    *color;
  321.  
  322.     x =    f->generic.x;
  323.     y =    f->generic.y;
  324.  
  325.     if (f->generic.flags & QMF_SMALLFONT)
  326.     {
  327.         w = SMALLCHAR_WIDTH;
  328.         h = SMALLCHAR_HEIGHT;
  329.         style = UI_SMALLFONT;
  330.     }
  331.     else
  332.     {
  333.         w = BIGCHAR_WIDTH;
  334.         h = BIGCHAR_HEIGHT;
  335.         style = UI_BIGFONT;
  336.     }    
  337.  
  338.     if (Menu_ItemAtCursor( f->generic.parent ) == f) {
  339.         focus = qtrue;
  340.         style |= UI_PULSE;
  341.     }
  342.     else {
  343.         focus = qfalse;
  344.     }
  345.  
  346.     if (f->generic.flags & QMF_GRAYED)
  347.         color = text_color_disabled;
  348.     else if (focus)
  349.         color = text_color_highlight;
  350.     else
  351.         color = text_color_normal;
  352.  
  353.     if ( focus )
  354.     {
  355.         // draw cursor
  356.         UI_FillRect( f->generic.left, f->generic.top, f->generic.right-f->generic.left+1, f->generic.bottom-f->generic.top+1, listbar_color ); 
  357.         UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|style, color);
  358.     }
  359.  
  360.     if ( f->generic.name ) {
  361.         UI_DrawString( x - w, y, f->generic.name, style|UI_RIGHT, color );
  362.     }
  363.  
  364.     MField_Draw( &f->field, x + w, y, style, color );
  365. }
  366.  
  367. /*
  368. ==================
  369. MenuField_Key
  370. ==================
  371. */
  372. sfxHandle_t MenuField_Key( menufield_s* m, int* key )
  373. {
  374.     int keycode;
  375.  
  376.     keycode = *key;
  377.  
  378.     switch ( keycode )
  379.     {
  380.         case K_KP_ENTER:
  381.         case K_ENTER:
  382.         case K_JOY1:
  383.         case K_JOY2:
  384.         case K_JOY3:
  385.         case K_JOY4:
  386.             // have enter go to next cursor point
  387.             *key = K_TAB;
  388.             break;
  389.  
  390.         case K_TAB:
  391.         case K_KP_DOWNARROW:
  392.         case K_DOWNARROW:
  393.         case K_KP_UPARROW:
  394.         case K_UPARROW:
  395.             break;
  396.  
  397.         default:
  398.             if ( keycode & K_CHAR_FLAG )
  399.             {
  400.                 keycode &= ~K_CHAR_FLAG;
  401.  
  402.                 if ((m->generic.flags & QMF_UPPERCASE) && Q_islower( keycode ))
  403.                     keycode -= 'a' - 'A';
  404.                 else if ((m->generic.flags & QMF_LOWERCASE) && Q_isupper( keycode ))
  405.                     keycode -= 'A' - 'a';
  406.                 else if ((m->generic.flags & QMF_NUMBERSONLY) && Q_isalpha( keycode ))
  407.                     return (menu_buzz_sound);
  408.  
  409.                 MField_CharEvent( &m->field, keycode);
  410.             }
  411.             else
  412.                 MField_KeyDownEvent( &m->field, keycode );
  413.             break;
  414.     }
  415.  
  416.     return (0);
  417. }
  418.  
  419.  
  420.